<?php

namespace App\CustHub\Service;

use App\Common\Constants\PayWayConstants;
use App\CustHub\Dto\RefundDto;
use App\CustHub\Mapper\ChUserMapper;
use App\CustHub\Vo\PaymentVo;
use App\CustHub\Vo\UserBalanceVo;
use App\Setting\Service\SettingConfigService;
use Hyperf\Di\Annotation\Inject;
use Mine\Abstracts\AbstractService;
use Mine\Exception\NormalStatusException;
use Mine\MineRequest;
use Yansongda\Artful\Exception\ContainerException;
use Yansongda\Artful\Exception\InvalidParamsException;
use Yansongda\Artful\Exception\ServiceNotFoundException;
use Yansongda\HyperfPay\Pay as BigPay;
use Yansongda\Pay\Pay;


class PaymentService extends AbstractService
{
    #[Inject]
    protected BigPay $pay;

    #[Inject]
    protected SettingConfigService $configService;

    /**
     * 支付宝支付
     * @return \Yansongda\Pay\Provider\Alipay
     */
    public function alipay(string $notifyUrl = '',string $returnUrl = ''): \Yansongda\Pay\Provider\Alipay
    {

        $payConfig = $this->configService->getConfigByGroupKey('pay_config');
        $payConfig = array_column($payConfig,'value','key');
//        // 必填-应用公钥证书 路径
//        'app_public_cert_path' => BASE_PATH.'/public/uploadfile/cert/appPublicCert.crt',
//                    // 必填-支付宝公钥证书 路径
//                    'alipay_public_cert_path' => BASE_PATH.'/public/uploadfile/cert/alipayPublicCert.crt',
//                    // 必填-支付宝根证书 路径
//                    'alipay_root_cert_path' => BASE_PATH.'/public/uploadfile/cert/alipayRootCert.crt',

        $config = [
            'alipay' => [
                'default' => [
                    // 必填-支付宝分配的 app_id
                    'app_id' => $payConfig['pay_aliay_appid'],
                    // 必填-应用私钥 字符串或路径
                    'app_secret_cert' => $payConfig['pay_alipay_app_secret_cert'],
                    // 必填-应用公钥证书 路径
                    'app_public_cert_path' =>  BASE_PATH.'/public'.$payConfig['pay_alipay_app_public_cert'],
                    // 必填-支付宝公钥证书 路径
                    'alipay_public_cert_path' => BASE_PATH.'/public'.$payConfig['pay_alipay_public_cert'],
                    // 必填-支付宝根证书 路径
                    'alipay_root_cert_path' => BASE_PATH.'/public'.$payConfig['pay_alipay_root_cert'],
                    'return_url' => $returnUrl,
                    'notify_url' => $notifyUrl,
                    // 选填-服务商模式下的服务商 id，当 mode 为 Pay::MODE_SERVICE 时使用该参数
                    'service_provider_id' => '',
                    // 选填-默认为正常模式。可选为： MODE_NORMAL, MODE_SANDBOX, MODE_SERVICE
                    'mode' => Pay::MODE_NORMAL,
                ],
            ]
        ];
        return $this->pay->alipay(array_merge($config, ['_force' => true]));
    }

    /**
     * 微信支付
     * @return \Yansongda\Pay\Provider\Wechat
     */
    public function wechat(string $notifyUrl = ''): \Yansongda\Pay\Provider\Wechat
    {
        $payConfig = $this->configService->getConfigByGroupKey('pay_config');
        $payConfig = array_column($payConfig,'value','key');

        $config = [
            'wechat' => [
                'default'=>[
                    // 必填-商户号，服务商模式下为服务商商户号
                    'mch_id' => $payConfig['mch_id'],
                    'mch_secret_key_v2' => $payConfig['mch_secret_key'],
                    // 必填-商户秘钥
                    'mch_secret_key' => $payConfig['mch_secret_key'],
                    // 必填-商户私钥 字符串或路径 apiclient_key.pem这个证书文件
                    'mch_secret_cert' => BASE_PATH.'/public'.$payConfig['mch_secret_cert'],
                    // 必填-商户公钥证书路径  apiclient_cert.pem 证书文件
                    'mch_public_cert_path' => BASE_PATH.'/public'.$payConfig['mch_public_cert_path'],
                    // 必填
                    'notify_url' => $notifyUrl,
                    // 选填-公众号 的 app_id
                    'mp_app_id' => $payConfig['mp_appid'],
                    // 选填-小程序 的 app_id
//                'mini_app_id' => '',
//                // 选填-app 的 app_id
//                'app_id' => '',
                    // 选填-默认为正常模式。可选为： MODE_NORMAL, MODE_SERVICE
                    'mode' => Pay::MODE_NORMAL,
                ]
            ],
        ];


        return $this->pay->wechat(array_merge($config, ['_force' => true]));
    }


    public function unifiedPay(PaymentVo $vo)
    {
        if($vo->getPayWay() == PayWayConstants::WECHAT){
            $order = [
                'out_trade_no' => $vo->getOrderNo(),
                'description' => $vo->getSubject(),
                'amount' => [
                    'total' => $vo->getPayAmount() * 100,
                ],
            ];
            //todo 待处理回调地址必须是https格式 且不能带参数 否则会报错
            try {
                $result =$this->wechat($vo->getNotifyUrl())->scan($order);

            }catch (\Throwable $e){
                logger()->error('调取微信支付接口异常'.$e->getMessage());
            }
        }elseif ($vo->getPayWay() == PayWayConstants::ALIPAY){
            $order = [
                'out_trade_no' => $vo->getOrderNo(),
                'total_amount' => $vo->getPayAmount(),
                'subject' => $vo->getSubject(),
                '_method' => 'get',
            ];

            $referer = container()->get(MineRequest::class)->getHeader('referer');
            if(!empty($referer)){
                $returnUrl = array_shift($referer);
            }else{
                $returnUrl = '';
            }

            $result = $this->alipay($vo->getNotifyUrl(),$returnUrl)
                ->web($order);
        }else{
            $user = container()->get(ChUserMapper::class)->findById($vo->getUid());
            if($user['money'] < $vo->getPayAmount()){
                throw new NormalStatusException('余额不足，请充值后再试~');
            }

            $result = container()->get(UserBalanceService::class)->updateBalance(new UserBalanceVo(
                uid: $vo->getUid(),
                money: $vo->getPayAmount(),
                businessType: $vo->getBusinessType(),
                order_id: $vo->getOrderId()
            ));

            if(!$result){
                throw new NormalStatusException('余额支付失败，请重新支付~');
            }
        }
        return $result;
    }

    public function refund(RefundDto $data)
    {
        if($data->getPayWay() == PayWayConstants::WECHAT){
            try {
                $result = $this->wechat($data->getNotifyUrl())->refund([
                    'out_trade_no' => $data->getOutTradeNo(),
                    'out_refund_no' => $data->getOutRefundNo(),
                    'amount' => [
                        'refund' => $data->getRefundAmount(),
                        'total' => $data->getTotalAmount(),
                        'currency' => 'CNY',
                    ],
                    '_action' => 'mini'
                ]);
            } catch (\Throwable $e) {
                throw new NormalStatusException('退款申请失败，请稍后重试');
            }
        }else{
            try {
                $result = $this->alipay($data->getNotifyUrl())->refund([
                    'out_trade_no' => $data->getOutTradeNo(),
                    'refund_amount' => $data->getRefundAmount(),
                    '_action' => 'scan'
                ]);
            } catch (\Throwable $e) {
                throw new NormalStatusException('退款申请失败，请稍后重试');
            }
        }

        return $result;
    }
}